package org.javahispano.javacup.tacticas_aceptadas.sistemasorp;

import java.awt.Color;
import org.javahispano.javacup.modelo.*;
import java.util.List;
import java.util.LinkedList;
import java.util.Random;

public class TacticaTestum implements Tactica {

    Posicion alineacion1[]=new Posicion[]{
        new Posicion(0,-51.5),
        new Posicion(-2,-51.5),
        new Posicion(2,-51.5),
        new Posicion(19.496503496503497,-13.540723981900454),
        new Posicion(-22.58741258741259,-14.728506787330318),
        new Posicion(-1.902097902097902,-10.352941176470589),
        new Posicion(24.251748251748253,-10.766968325791854),
        new Posicion(-28.293706293706293,18.766968325791854),
        new Posicion(-0.7132867132867133,34.20814479638009),
        new Posicion(-19.97202797202797,34.20814479638009),
        new Posicion(19.734265734265733,34.20814479638009)
    };

    Posicion alineacion2[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-19.734265734265733,-34.20814479638009),
        new Posicion(-0.4755244755244755,-21.142533936651585),
        new Posicion(19.25874125874126,-33.49547511312217),
        new Posicion(8.797202797202797,-7.839366515837104),
        new Posicion(-14.74125874125874,-0.7126696832579186),
        new Posicion(-30.67132867132867,-2.1380090497737556),
        new Posicion(24.965034965034967,-1.900452488687783),
        new Posicion(-8.55944055944056,-7.126696832579185),
        new Posicion(-23.538461538461537,-1.6628959276018098),
        new Posicion(19.020979020979023,-1.4253393665158371)
    };

    Posicion alineacion3[]=new Posicion[]{
        new Posicion(0.2595419847328244,-50.41044776119403),
        new Posicion(-11.16030534351145,-31.082089552238806),
        new Posicion(11.16030534351145,-31.6044776119403),
        new Posicion(27.251908396946565,-27.94776119402985),
        new Posicion(-29.84732824427481,-26.902985074626866),
        new Posicion(0.23776223776223776,0.0),
        new Posicion(-22.349650349650346,-0.7126696832579186),
        new Posicion(27.34265734265734,-1.1877828054298643),
        new Posicion(-29.244755244755243,-1.4253393665158371),
        new Posicion(-13.314685314685315,-1.1877828054298643),
        new Posicion(-1.4265734265734267,-11.165158371040723)
    };

    class TacticaDetalleImpl implements TacticaDetalle {

        public String getNombre() {
            return "testum";
        }

        public String getPais() {
            return "España";
        }

        public String getEntrenador() {
            return "Oscar Rodriguez";
        }

        public Color getColorCamiseta() {
            return new Color(255, 0, 0);
        }

        public Color getColorPantalon() {
            return new Color(0, 255, 0);
        }

        public Color getColorFranja() {
            return new Color(255, 255, 255);
        }

        public Color getColorCalcetas() {
            return new Color(255, 255, 0);
        }

        public Color getColorPortero() {
            return new Color(0, 0, 0        );
        }

        public EstiloUniforme getEstilo() {
            return EstiloUniforme.LINEAS_HORIZONTALES;
        }

        public Color getColorCamiseta2() {
            return new Color(93, 27, 241);
        }

        public Color getColorPantalon2() {
            return new Color(252, 184, 31);
        }

        public Color getColorFranja2() {
            return new Color(223, 102, 103);
        }

        public Color getColorCalcetas2() {
            return new Color(54, 63, 221);
        }

        public Color getColorPortero2() {
            return new Color(158, 121, 38        );
        }

        public EstiloUniforme getEstilo2() {
            return EstiloUniforme.FRANJA_DIAGONAL;
        }

        class JugadorImpl implements JugadorDetalle {

            String nombre;
            int numero;
            Color piel, pelo;
            double velocidad, remate, presicion;
            boolean portero;
            Posicion posicion;

            public JugadorImpl(String nombre, int numero, Color piel, Color pelo,
                    double velocidad, double remate, double presicion, boolean portero) {
                this.nombre=nombre;
                this.numero=numero;
                this.piel=piel;
                this.pelo=pelo;
                this.velocidad=velocidad;
                this.remate=remate;
                this.presicion=presicion;
                this.portero=portero;
            }

            public String getNombre() {
                return nombre;
            }

            public Color getColorPiel() {
                return piel;
            }

            public Color getColorPelo() {
                return pelo;
            }

            public int getNumero() {
                return numero;
            }

            public boolean esPortero() {
                return portero;
            }

            public double getVelocidad() {
                return velocidad;
            }

            public double getRemate() {
                return remate;
            }

            public double getPresicion() {
                return presicion;
            }

        }

        public JugadorDetalle[] getJugadores() {
            return new JugadorDetalle[]{
                new JugadorImpl("Lucas", 1, new Color(255,200,150), new Color(50,0,0),1.0d,1.0d,0.72d, true),
                new JugadorImpl("Ramon", 2, new Color(255,200,150), new Color(50,0,0),1.0d,1.0d,0.75d, false),
                new JugadorImpl("Sebasti�n", 3, new Color(255,200,150), new Color(50,0,0),1.0d,1.0d,0.75d, false),
                new JugadorImpl("Pedro", 4, new Color(255,200,150), new Color(50,0,0),1.0d,1.0d,0.76d, false),
                new JugadorImpl("Raul", 5, new Color(255,200,150), new Color(50,0,0),1.0d,0.67d,0.27d, false),
                new JugadorImpl("Israel", 6, new Color(255,200,150), new Color(50,0,0),1.0d,0.6d,0.22d, false),
                new JugadorImpl("Iv�n", 7, new Color(255,200,150), new Color(50,0,0),1.0d,0.62d,0.26d, false),
                new JugadorImpl("Esteban", 8, new Color(255,200,150), new Color(50,0,0),1.0d,0.61d,0.32d, false),
                new JugadorImpl("Ricardo", 9, new Color(255,200,150), new Color(50,0,0),1.0d,1.0d,1.0d, false),
                new JugadorImpl("Miguel", 10, new Color(255,200,150), new Color(50,0,0),1.0d,0.95d,1.0d, false),
                new JugadorImpl("Angel", 11, new Color(255,200,150), new Color(50,0,0),1.0d,1.0d,1.0d, false)
            };}
        }

    TacticaDetalle detalle=new TacticaDetalleImpl();
    public TacticaDetalle getDetalle() {
        return detalle;
    }

    public Posicion[] getPosicionSaca(SituacionPartido sp) {
    return alineacion3;
    }

    public Posicion[] getPosicionRecive(SituacionPartido sp) {
    return alineacion2;
    }

    LinkedList<Comando> comandos = new LinkedList<Comando>();
    Posicion balonAnterior = null;
    Posicion balonActual = null;
    SituacionPartido sp = null;
    int nVelocidad = 0;
    Posicion[] misJugadores = null;
    Posicion[] rivales = null;
    JugadorDetalle detalles[] = null;
   
    int nJugadorPasado = 10;
   
    public List<Comando> ejecutar(SituacionPartido sp) {
       
       
        if(balonAnterior == null)
        {
            balonAnterior = sp.balon();
        }
        balonActual = sp.balon();
        this.sp = sp;
        misJugadores = sp.misJugadores();
        rivales = sp.rivales();
        detalles = sp.detalleMisJugadores();

        comandos.clear();

        // jugadores especiales a sus posiciones
        for(int nIndice = 0; nIndice < 3; nIndice++)
        {
            comandos.add(new ComandoIrA(nIndice, alineacion1[nIndice]));
        }
       
        // resto jugadores a sus posiciones
        for(int nIndice = 3; nIndice < 11; nIndice++)
        {
            comandos.add(new ComandoIrA(nIndice, centroide(nIndice)));
        }
       

        // defensa
        int rivalesCercaPorteria[] = Constantes.centroArcoInf.indicesMasCercanos(rivales);
        int excluye[] = {0, 1, 2, -1, -1, -1};
        int nIndiceExcluye = 3;
        for(int nIndice = 0; nIndice < rivalesCercaPorteria.length; nIndice++)
        {
                if(rivales[rivalesCercaPorteria[nIndice]].getY() < -1)
                {
                    int indicesMasCercanos[] = rivales[rivalesCercaPorteria[nIndice]].indicesMasCercanos(misJugadores, excluye);
                   
                   
                   
                    Posicion defensa = situaVertical(rivales[rivalesCercaPorteria[nIndice]], 3);
                    comandos.add(new ComandoIrA(indicesMasCercanos[0], defensa));
                    excluye[nIndiceExcluye] = indicesMasCercanos[0];
                    nIndiceExcluye++;
                    if(nIndiceExcluye == excluye.length)
                    {
                        break;
                    }
                }
        }
       
        // porteros
        if(sp.balon().distancia(misJugadores[0]) < 8)
        {
            Posicion portero = prediceBalon(3);
            double x = Math.min(Math.max(portero.getX(), -3), 3);
            x -= 0.5;
            double y = Math.max(Constantes.centroArcoInf.getY(), Math.min(-50, portero.getY()));
            comandos.add(new ComandoIrA(0, new Posicion(x, y)));
            comandos.add(new ComandoIrA(1, dondeMejor(1)));
            comandos.add(new ComandoIrA(2, dondeMejor(2)));
        }

        // a por la bola
        int indiceMasCercanos[] = sp.balon().indicesMasCercanos(misJugadores);
        int nIndicex = 0;
        while(indiceMasCercanos[nIndicex] == 0 || indiceMasCercanos[nIndicex] == 1 || indiceMasCercanos[nIndicex] == 2)
        {
            nIndicex++;
        }
        comandos.add(new ComandoIrA(indiceMasCercanos[nIndicex], dondeMejor(indiceMasCercanos[nIndicex])));
       
        // tiro
        int remate[] = sp.puedenRematar();
       
        Random random = new Random();
        
        for(int nIndice = 0; nIndice < remate.length; nIndice++)
        {
            if(sp.balon().getY() < 30)
            {
                int rivalMasCercano[] = misJugadores[remate[nIndice]].indicesMasCercanos(rivales);
                if(rivales[rivalMasCercano[0]].distancia(sp.balon()) > 15 || rivales[rivalMasCercano[0]].getY() + 1 < misJugadores[remate[nIndice]].getY())
                {
                    double fuerza = 0.35 / detalles[remate[nIndice]].getRemate();
                    comandos.add(new ComandoGolpearBalon(remate[nIndice], Constantes.centroArcoSup, fuerza, false));
                }
                else if(sp.balon().getY() > -35)
                {
                	int mios[] = misJugadores[remate[nIndice]].indicesMasCercanos(misJugadores);
                	int nSuma = 0;
                	while(misJugadores[remate[nIndice]].getY() >= misJugadores[mios[nSuma]].getY() 
                			|| misJugadores[remate[nIndice]].distancia(misJugadores[mios[nSuma]]) < 5
                			|| (mios[nSuma] == 0 || mios[nSuma] == 1 || mios[nSuma] == 2) )
                	{
                		nSuma++;
                		if(nSuma == mios.length)
                		{
	        				do
	        				{
	        					nSuma = random.nextInt(mios.length);
	        				}
	        				while(mios[nSuma] == 0);
                			break;
                		}
                	}
                	nJugadorPasado = mios[nSuma];
                	double fuerza = sp.balon().distancia(misJugadores[mios[nSuma]]) / detalles[remate[nIndice]].getRemate() * 0.75 / 20 * 1.05;
                	if(rivales[rivalMasCercano[0]].distancia(sp.balon()) < 12)
                	{
                		comandos.add(new ComandoGolpearBalon(remate[nIndice], Constantes.centroArcoSup, 1, true));
                	}
                	else
                	{
                		comandos.add(new ComandoGolpearBalon(remate[nIndice], misJugadores[mios[nSuma]], fuerza, true));
                	}
                }
                else
                {
                	comandos.add(new ComandoGolpearBalon(remate[nIndice], Constantes.centroArcoSup, 1, true));
                }
            }
            else
            {
                if(sp.balon().getY() > 43)
                {
                	comandos.add(new ComandoGolpearBalon(remate[nIndice], Constantes.centroArcoSup, 1, false));
                }
                else if(sp.balon().getY() > 32)
                {
                	double fuerza = sp.balon().distancia(Constantes.centroArcoSup) / detalles[remate[nIndice]].getRemate() * 0.75 / 20 * 1.13;
                	comandos.add(new ComandoGolpearBalon(remate[nIndice], Constantes.centroArcoSup, fuerza, true));
                }
                else
                {
                	comandos.add(new ComandoGolpearBalon(remate[nIndice], Constantes.centroArcoSup, 1, true));
                }          
            }
        }
        comandos.add(new ComandoIrA(nJugadorPasado, dondeMejor(nJugadorPasado)));
        balonAnterior = balonActual;
        return comandos;
    }
   
    Posicion situaVertical(Posicion contrario, double distancia)
    {
        double angulo = sp.balon().angulo(contrario);
        double x = contrario.getX() - (Math.cos(angulo) * distancia);
        double y = contrario.getY() - (Math.sin(angulo) * distancia);
       
        return new Posicion(x, y);
    }
   
    Posicion centroide(int nJugador)
    {
        int contrarios[] = alineacion1[nJugador].indicesMasCercanos(rivales);
        Posicion uno = rivales[contrarios[0]];
        Posicion dos = rivales[contrarios[1]];
        double x = (uno.getX() + dos.getX() + alineacion1[nJugador].getX() + sp.balon().getX()) / 4;
        double y = (uno.getY() + dos.getY() + alineacion1[nJugador].getY() + sp.balon().getY()) / 4;
        return new Posicion(x, y);
    }
   
    Posicion dondeMejor(int jugador)
    {
        double distancia = 1000;
        Posicion posicion = null;
       
        for(int i=1; i < 100; i++)
        {
            Posicion actual = prediceBalon(i);
           
            if(distancia > actual.distancia(misJugadores[jugador]))
            {
                distancia = actual.distancia(misJugadores[jugador]);
                posicion = actual;
            }
            if(distancia <= 5 && alturaX <= Constantes.ALTURA_CONTROL_BALON) break;
        }
        return posicion;
    }
   
    double alturaX = 0;
    Posicion prediceBalon(int iteraciones)
    {
        double velocidadX = Math.abs(balonActual.getX() - balonAnterior.getX()); 
        double velocidadY = Math.abs(balonActual.getY() - balonAnterior.getY());
        double x = balonActual.getX();
        double y = balonActual.getY();
        alturaX = sp.alturaBalon();
        int iteracionesX = iteraciones;
        if(balonActual.getX() > balonAnterior.getX())
        {
            while(iteracionesX > 0)
            {
                alturaX = Math.round((alturaX - Constantes.G) / Constantes.G) * Constantes.G;
                if(alturaX > 0)
                {
                    velocidadX *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                }
                else
                {
                    alturaX = (-alturaX - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                    alturaX = Math.round((alturaX - Constantes.G) / Constantes.G) * Constantes.G;
                    velocidadX *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                }
                if(velocidadX == 0)
                    break;
                x += velocidadX;
                iteracionesX--;
               
            }
        }
        else
        {
            while(iteracionesX > 0)
            {
                alturaX = Math.round((alturaX - Constantes.G) / Constantes.G) * Constantes.G;
                if(alturaX > 0)
                {
                    velocidadX *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                }
                else
                {
                    alturaX = (-alturaX - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                    alturaX = Math.round((alturaX - Constantes.G) / Constantes.G) * Constantes.G;
                    velocidadX *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                }
                if(velocidadX == 0)
                    break;
                x -= velocidadX;
                iteracionesX--;
               
            }
        }

        double alturaY = sp.alturaBalon();
        int iteracionesY = iteraciones;
        if(balonActual.getY() > balonAnterior.getY())
        {
            while(iteracionesY > 0)
            {
                alturaY = Math.round((alturaY - Constantes.G) / Constantes.G) * Constantes.G;
                if(alturaY > 0)
                {
                    velocidadY *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                }
                else
                {
                    alturaY = (-alturaY - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                    alturaY = Math.round((alturaY - Constantes.G) / Constantes.G) * Constantes.G;
                    velocidadY *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                }
                if(velocidadY == 0)
                    break;
                y += velocidadY;
                iteracionesY--;
            }
        }
        else
        {
            while(iteracionesY > 0)
            {
                alturaY = Math.round((alturaY - Constantes.G) / Constantes.G) * Constantes.G;
                if(alturaY > 0)
                {
                    velocidadY *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
                }
                else
                {
                    alturaY = (-alturaY - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
                    alturaY = Math.round((alturaY - Constantes.G) / Constantes.G) * Constantes.G;
                    velocidadY *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
                }
                if(velocidadY == 0)
                    break;
                y -= velocidadY;
                iteracionesY--;
               
            }
        }
        return new Posicion(x,y);
    }
  
}